package com.example.demo.java8.jicheng;

import com.example.demo.java8.jicheng.one.Dongwu;
import com.example.demo.java8.jicheng.three.KeJi;
import com.example.demo.java8.jicheng.three.Zhonghua;
import com.example.demo.java8.jicheng.two.Gou;
import com.example.demo.java8.jicheng.two.Niu;

import java.util.ArrayList;
import java.util.List;

/**
 * 测试 继承关系
 *
 * Java泛型声明<? extends E>和<? super E>的作用和区别
 *
 * https://www.cnblogs.com/xiarongjin/p/8309755.html
 *
 * 为什么要引入泛型通配符？一句话：为了保证类型安全。
 * PECS法则：生产者（Producer）使用extends，消费者（Consumer）使用super
 * 具体请看 《effective java》里，Joshua Bloch提出的PECS原则：
 * 频繁往外读取内容的，适合用上界Extends。
 * 经常往里插入的，适合用下界Super。
 *
 * @author luowj12
 * @since 2021/5/10 14:35
 */
public class JichengTest {

    public static void main(String[] args) {
        //Gou gou = new Dongwu();//编译不通过，父类无法隐性转为子类
        Gou gou = (Gou)new Dongwu();//需要强转，但是运行会报错
        //子类可以隐性转为父类
        Dongwu dongwu = new Niu();
        dongwu = new Gou();
        System.out.println(dongwu.name);
        /*******************************  <? extends E>  ************************************/
         //<? extends E> 是 Upper Bound（上限） 的通配符，用来限制元素的类型的上限，比如
        List<? extends Gou> dongwuList;
        //表示集合中的元素类型上限为Gou类型，即只能是Gou或者Gou的子类，因此对于下面的赋值是合理的
        dongwuList = new ArrayList<Gou>();
        dongwuList = new ArrayList<KeJi>();
        dongwuList = new ArrayList<Zhonghua>();
        //Gou的父类编译将不通过
        //dongwuList = new ArrayList<Dongwu>();//编译不通过
        //dongwuList = new ArrayList<Object>();//编译不通过
        //写入:因为集合dongwuList中装的元素类型为Gou或Gou子类，直觉告诉我们，往dongwuList中添加一个Gou类型对象或其子类对象是可行的
        //结果是编译不通过的,为什么？因为<? extends Gou>只是告诉编译器集合中元素的类型上限，但它具体是什么类型编译器是不知道的
        //既然是不确定的，为了类型安全，编译器只能阻止添加元素了
        //dongwuList.add(new Gou());编译不通过
        //dongwuList.add(new Dongwu());编译不通过
        //dongwuList.add(new KeJi());编译不通过
        //读取:无论dongwuList指向什么，编译器都可以确定获取的元素是Gou类型，所有读取集合中的元素是允许的
        //KeJi keji = dongwuList.get(0);编译不通过
        Gou gou1 = dongwuList.get(0);//编译通过
        //补充：<?>是<? extends Object>的简写

        /*******************************  <? super E>  ************************************/
        // <? super E> 是 Lower Bound（下限） 的通配符 ，用来限制元素的类型下限，比如
        List<? super Gou> dongwuList1;
        //表示集合中元素类型下限为Gou类型，即只能是Gou或Gou的父类，因此对于下面的赋值是合理的
        dongwuList1 = new ArrayList<Gou>();
        dongwuList1 = new ArrayList<Dongwu>();
        dongwuList1 = new ArrayList<Object>();
        //如果元素类型为Gou的子类，则编译不同过
        //dongwuList1 = new ArrayList<KeJi>();编译不通过
        //dongwuList1 = new ArrayList<Zhonghua>();编译不通过
        // 写入:因为dongwuList1中装的元素是Gou或Gou的某个父类，我们无法确定是哪个具体类型，但是可以确定的是Gou和Gou的子类是和这个“不确定的类”兼容的，
        // 因为它肯定是这个“不确定类型”的子类，也就是说我们可以往集合中添加Gou或者Gou子类的对象，所以对于下面的添加是允许的
        dongwuList1.add(new KeJi());
        dongwuList1.add(new Gou());
        //dongwuList1.add(new Dongwu());编译不通过
        //读取:编译器允许从dongwuList1中获取元素的，但是无法确定的获取的元素具体是什么类型，只能确定一定是Object类型的子类，因此我们想获得存储进去的对应类型的元素就只能进行强制类型转换了
        //KeJi keji1 = dongwuList1.get(0);编译不通过
        //Dongwu dongwu = dongwuList1.get(0);编译不通过
        //Gou gou2 = dongwuList1.get(0);编译不通过
        //只能强转
        KeJi keji1 = (KeJi)dongwuList1.get(0);//强转
        //Dongwu dongwu = (Dongwu)dongwuList1.get(0);编译不通过
        Gou gou2 = (Gou)dongwuList1.get(0);//强转
    }

}
